//
// Created by sgyt on 2020/2/14.
// 创造一个孤儿进程，知道内核在创建孤儿进程的过程

/**
 * 代码总纲
 * 1.父进程睡5秒，
 * 2.子进程为挂断信号建立信号处理程序（收到父进程结束发出的信号）
 * 3.子进程kill函数向自身发出停止信号，类似于ctrl+z停止一个前台作业
 * 4.当父进程终止。该子进程变成孤儿进程，父id成为1，系统管理，子进程变成一个孤儿进程组的成员（进程组id不变）
 * 5.父进程终止后，进程组包含一个停止的进程，进程组成为孤儿进程组，要求向新孤儿进程组中处于停止状态的每一个进程发送挂断信号，接着又向其发送继续信号
 * 6.在处理挂断信号后，子进程继续，对挂断信号的系统默认动作是终止进程，为此必须提供一个信号处理的程序已捕捉信号
 * @param argc
 * @param argv
 * @return
 */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

//信号接收
static void sig_hup(int signo)
{
    printf("SIGHUP received,pid = %d\n",getpid());
    fflush(stdout);
}

static void sig_cont(int signo)
{
    printf("SIGCONT received,pid = %d\n",getpid());
    fflush(stdout);
}

static void pr_ids(char *name)
{
    printf("%s:pid = %d,ppid = %d,pgrp = %d,tpgrp = %d\n",name,getpid(),getppid(),getpgrp(),tcgetpgrp(STDOUT_FILENO));
    fflush(stdout);
}


int main(int argc,char *argv[])
{
    char c;
    pid_t pid;

    pr_ids("parent");
    pid = fork();
    if(pid < 0)
    {
        perror("fork is error");
        exit(0);
    } else if (pid > 0)
    {
        sleep(5);//沉睡5秒，让子线程自己停止
    }else{
        pr_ids("child");
        //信号点方法注册
        signal(SIGHUP,sig_hup);
        signal(SIGCONT,sig_cont);
        //子进程发送自己停止信号
        kill(getpid(),SIGSTOP);
        //sleep(6);
        pr_ids("child");
        if(read(STDIN_FILENO,&c,1) != 1)
        {
            printf("read error %d on controlling\n",errno);
        }

    }

    return 0;
}

/**
 * 输出是：
 *
parent:pid = 9483,ppid = 7833,pgrp = 9483,tpgrp = 9483
child:pid = 9484,ppid = 9483,pgrp = 9483,tpgrp = 9483
SIGHUP received,pid = 9484
child:pid = 9484,ppid = 1,pgrp = 9483,tpgrp = 9483
 */
